package 学习JDBC;

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.*;

public class AdvanceQueryTest {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet r = null;
        try {
            //先创建数据库连接池，再通过连接池获取数据库连接对象
            DataSource ds = new MysqlDataSource();
            //创建数据库连接池：初始化时，就会创建一定数量的数据库连接，这些连接对象是可以重复使用，效率更高
            //整个url带参数可以只使用setURL方法，也可以将参数调用方法的方式来设置
            ((MysqlDataSource) ds).setURL("jdbc:mysql://localhost:3306/java43");
            ((MysqlDataSource) ds).setUser("root");
            ((MysqlDataSource) ds).setPassword("123456");
            ((MysqlDataSource) ds).setUseUnicode(true);
            ((MysqlDataSource) ds).setCharacterEncoding("UTF-8");
            ((MysqlDataSource) ds).setUseSSL(false);
            conn = ds.getConnection();

            System.out.println(conn);

//            //通过连接对象创建操作命令对象Statement（使用jdbc中的），该对象是用于操作sql的一个抽象的对象
//            s = conn.createStatement();
//            //查询：模拟在页面上，输入学生姓名来搜索学生
////            String queryName = "许仙";//能正常查询的输入
//            String queryName = "skdjsj' or '1'='1";//SQL注入：使用简单的操作命令对象，在拼接sql字符串，就可能出现安全问题
//
//            // （1）调用Statement操作命令对象的executeQuery(sql)
//            // （2）返回一个ResultSet结果集对象（查询sql执行的结果集）
//            String sql = "select id,sn,name,qq_mail,classes_id from student where name='"+queryName+"'";
//            System.out.println(sql);
//            r = s.executeQuery(sql);

            //要解决以上安全问题，需要调整以上操作命令对象为PreparedStatement
            String queryName = "skdjsj' or '1'='1";
            int queryId = 6;
            //准备一个带?占位符的sql
            String sql = "select id,sn,name,qq_mail,classes_id from student where name=? or id=?";
            ps = conn.prepareStatement(sql);//创建预编译的操作命令对象
            //替换占位符：调用setXXX方法，第一个参数，表示第几个占位符（从1开始），第二个参数，表示要替换的值
            ps.setString(1, queryName);//替换的值是什么类型，就调用setXXX方法
            ps.setInt(2, queryId);

            //执行sql，需要使用无参的方法
            r = ps.executeQuery();

            //处理结果集：结果集可能是多行数据，需要遍历来获取
            // 调用next就移动到下一行，返回true代表该行有数据，返回false代表该行没有数据
            while (r.next()) {//一直遍历到最后
                //进入循环，代表操作遍历的一行数据
                int id = r.getInt("id");
                String sn = r.getString("sn");
                String name = r.getString("name");
                String qqMail = r.getString("qq_mail");
                int classesId = r.getInt("classes_id");
                System.out.printf("id=%s, sn=%s, name=%s, qqMail=%s, classesId=%s\n",
                        id, sn, name, qqMail, classesId);
            }
        }finally {//无论如何，都要释放资源
            //释放资源：
            //（1）无论什么情况（异常）
            //（2）释放的顺序，和创建的顺序要相反（结果集对象，操作命令对象，数据库连接对象）
            if(r != null)//出现异常的时候，对象可能还没有赋值（初始化），调用close就会出现空指针异常
                r.close();
            if(ps != null)
                ps.close();
            if(conn != null)
                conn.close();
        }

    }
}
